//
//  ST_RecorderController.swift
//  btvideo
//
//  Created by mac on 2021/9/8.
//  Copyright © 2021 JarvanZhang. All rights reserved.
//

import Foundation
import RxSwift
import RxCocoa

class ST_RecorderController: NSObject {
    
    /// 录音文件地址
    let url: URL = {
        let url = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first!.appendingPathComponent("quickMessage.wav")
        return url
    }()
    
    var player: AVAudioPlayer?
    
    /// 播放时间
    let playing_time = BehaviorRelay<TimeInterval>(value: 0)
    /// 是否正在播放
    let isPlaying = BehaviorRelay<Bool>(value: false)
    /// 播放结束
    let on_playing_finished = PublishSubject<Void>()
    var playDisposable: Disposable?
    
    var audio_session: AVAudioSession = {
        let session = AVAudioSession.sharedInstance()
        return session
    }()
    
    var recorder: AVAudioRecorder?
    
    /// 最长录音时间
    let max_recording_time: TimeInterval = 60
    /// 录音时间
    let recording_time = BehaviorRelay<TimeInterval>(value: 0)
    /// 是否正在录制
    let isRecording = BehaviorRelay<Bool>(value: false)
    /// 录音结束
    let on_recording_finished = PublishSubject<Void>()
    var recordDisposable: Disposable?
    
    var playing_cell: ST_QuickMessageContentItem?
    
    deinit {
        try? audio_session.setActive(false)
        player?.stop()
        recorder?.stop()
        recorder?.deleteRecording()
    }
    
    /// 播放录音
    func play() {
        do {
            try self.audio_session.setCategory(.playback, mode: .default)
            try self.audio_session.setActive(true)
            player = try AVAudioPlayer(contentsOf: url)
            player?.delegate = self
            player?.prepareToPlay()
            player?.play()
            isPlaying.accept(true)
            trace_playing_time()
        } catch {
            fatalError(error.localizedDescription)
        }
    }
    
    
    /// 播放制定URL的声音
    /// - Parameters:
    ///   - url: 声音URL
    ///   - cell: 播放动画的cell
    func play(url: URL, cell: ST_QuickMessageContentItem) {
        
        guard !(player?.isPlaying ?? false) else {
            stop_playing()
            isPlaying.accept(false)
            return
        }
        
        stop_playing()
        playing_cell = cell
        
        do {
            try self.audio_session.setCategory(.playback, mode: .default)
            try self.audio_session.setActive(true)
            player = try AVAudioPlayer(data: Data(contentsOf: url))
            player?.delegate = self
            player?.prepareToPlay()
            player?.play()
            isPlaying.accept(true)
            cell.voice_button.imageView?.startAnimating()
            trace_playing_time()
        } catch {
            fatalError(error.localizedDescription)
        }
    }
    
    /// 停止播放
    func stop_playing() {
        
        playing_cell?.voice_button.imageView?.stopAnimating()
        playing_cell = nil
        player?.stop()
        isPlaying.accept(false)
        
    }
    
    /// 更新播放时间
    func trace_playing_time() {
        
        guard player?.isPlaying ?? false else { return }
        
        playDisposable =
            Observable<Int>.timer(.milliseconds(0), period: .milliseconds(100), scheduler: MainScheduler.instance)
                .asDriver(onErrorJustReturn: 0)
                .drive(onNext: { [weak self] _ in
                    self?.playing_time.accept(self?.player?.currentTime ?? 0)
                })
    }
    
    /// 请求麦克风权限
    /// - Parameter completion: 结果
    func requestRecordPermission(completion: @escaping (Result<Bool, Error>) -> Void) {
        
        do {
            try self.audio_session.setCategory(.record, mode: .default)
            try self.audio_session.setActive(true)
            self.audio_session.requestRecordPermission() { allowed in
                DispatchQueue.main.async {
                    completion(.success(allowed))
                }
            }
        } catch {
            completion(.failure(error))
        }
        
    }
    
    
    /// 开始录制
    func record() {
        
        requestRecordPermission { [weak self] result in
            guard let self = self else { return }
            
            if self.recorder == nil {
                do {
                    self.recorder = try AVAudioRecorder(url: self.url, settings: [
                        AVFormatIDKey: kAudioFormatLinearPCM,
                        AVSampleRateKey: 8000,
                        AVNumberOfChannelsKey: 1,
                        AVLinearPCMBitDepthKey: 16,
                        AVLinearPCMIsNonInterleaved: false,
                        AVLinearPCMIsFloatKey: false,
                        AVLinearPCMIsBigEndianKey: false
                    ])
                    self.recorder?.delegate = self
                } catch {
                    fatalError(error.localizedDescription)
                }
            }
            
            guard !(self.recorder?.isRecording ?? false) else { return }
            self.recorder?.record()
            self.isRecording.accept(true)
            self.trace_recording_time()
        }
        
    }
    
    /// 更新录制时间
    func trace_recording_time() {
        
        recordDisposable =
            Observable<Int>.timer(.milliseconds(0), period: .milliseconds(100), scheduler: MainScheduler.instance)
                .asDriver(onErrorJustReturn: 0)
                .drive(onNext: { [weak self] _ in
                    guard let self = self else { return }
                    self.recording_time.accept(self.recorder?.currentTime ?? 0)
                    if (self.recorder?.currentTime ?? 0) >= self.max_recording_time {
                        self.recording_time.accept(round(self.recorder?.currentTime ?? 0))
                        self.recorder?.stop()
                        self.isRecording.accept(false)
                        self.recordDisposable?.dispose()
                    }
                })
    }
    
    /// 停止录制
    func stop_recording() {
        
        guard recorder?.isRecording == true else { return }
        recorder?.stop()
        self.isRecording.accept(false)
        
    }
}

extension ST_RecorderController: AVAudioPlayerDelegate {
    
    func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
        playing_cell?.voice_button.imageView?.stopAnimating()
        playing_cell = nil
        isPlaying.accept(false)
        playDisposable?.dispose()
        on_playing_finished.onNext(())
    }
    
    func audioPlayerDecodeErrorDidOccur(_ player: AVAudioPlayer, error: Error?) {
        playing_cell?.voice_button.imageView?.stopAnimating()
        playing_cell = nil
        isPlaying.accept(false)
        playDisposable?.dispose()
        on_playing_finished.onNext(())
    }
}

extension ST_RecorderController: AVAudioRecorderDelegate {
    
    func audioRecorderDidFinishRecording(_ recorder: AVAudioRecorder, successfully flag: Bool) {
        isRecording.accept(false)
        recordDisposable?.dispose()
        on_recording_finished.onNext(())
    }
    
    func audioRecorderEncodeErrorDidOccur(_ recorder: AVAudioRecorder, error: Error?) {
        isRecording.accept(false)
        recordDisposable?.dispose()
        on_recording_finished.onNext(())
    }
}
